#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#include<string.h>



//VERY IMPORTANT
//TO write in file 465 there is function ,at line which is commented 
//Decomment line number 465   ,THE FUNCTION DOES NOT ALLOW ADDING ENTRIES HAVING SAME USER ID'S IN THE FILE
//tHIS IS BECAUSE UIDS HAVE TO BE DIFFERENT


//TO VARY ALPHA GIVE DIFFERENT NUMBER OF ELEMENTS






int flagest=0;
int ric=0;
//This is structure that stores in hash table
struct node
{
	char username[80];
	char password[80];
} p1[40];
//Our hash table is array of structures

//size of hash table is 40, hence maximum posssible enteries can be 40 ,as by open addressing scheme, alpha<1.

int ascii(char s[80]) //THIS IS FIRST HASH FUNCTION
{		      //THIS CALCULATES SUM OF ASCII VALUES OF ALL CHARACTERS IN USER ID AND TAKES MOD OF SIZE OF HASH TABLE. 
	
// best case time: when all uids have sum oF ascii characters as different.

//worst case time:when all the userid's have same ascii value sum eg u1="ABC", u2="CAB".

// average case time :when some userids have same ascii value sum.


	char ch;
	int i;        
	int key=0;
	int hash=0;
	for(i=0;i<=strlen(s)-1;i++)
	{
		key=key+s[i];
	}
	hash= key%40;

	return hash;
}


int ascii2(char s[80])
{
	char ch;//THIS CALCULATES SUM OF ASCII VALUES OF ALL CHARACTERS IN USER NAME AND TAKES MOD OF SIZE OF HASH TABLE,THEN 
	int i; //MULTIPLY BY 0.7 ,TAKE FRACTIONAL PART OF IT  
	int key=0;//mULTIPLY BY NO OF SLOTS
	int hu=0;//WE will get number in range 0 to 39,as 40 multiplied with a no smaller of equal to one.
	float t=0;
	int hash=0;   	
// best case: when all uids have different sum of ascii and fractional part obtained is different

//worst case:when all uids have same sum of ascii and fractional part obtained is different

// average case :when some uids have different sum of ascii and fractional part obtained is different
	for(i=0;i<=strlen(s)-1;i++)
	{
		key=key+s[i];
	}
	hu= key%40;
	t=hu*0.7;
	hash=40*(t-(int)t);
	return hash;
}





int ascii3(char s[80])
{
	char ch;//First character ascii is multiplied with length of string and mod size hash table is taken
	int i;
	// best case time: when all uids have different ascii(first characters)*len string value.

//worst case time:when all uids have same ascii(first characters)*len string value.,eg ."AB" &"AA"

// average case time :when some uids have different ascii(first characters)*len string value.
	int key=0;
	int hu=0;
	float t=0;
	int hash=0;


	hu= s[0]*strlen(s);
	hash=hu %40;
	return hash;
}





int probe(int ift) //This is to implement linear probing
{
	int fi=0;
	int o=0;
	fi=ift;
	if((strcmp(p1[ift].username,"")==0))
	{
		return fi;}
	else
	{	
		while((strcmp(p1[fi].username,"")!=0))
		{
			o++;
			fi=(ift +o)%40;		
		continue;
		}
		return fi;
	}


}




void filewrite() //This will create a text file Without duplicate ids
{
	int flag=0;
	char s[80];
	char j[80];

	FILE *fp;

	int count =0;
	fp=fopen("user.TXT","w");

	if (fp == NULL)
	{
		puts ("Cannot open file") ;
		exit(0);
	}
	printf("\n Creating file");
	printf("\n Enter user-id password in 1 line seperated by space ,Enter to terminate \n");

	fclose(fp);
	while( strlen  (gets(s))>0)//take every user id ,close file in wrting mode
	{	
		 flag =0; //open file in reading mode 
		fp=fopen("user.TXT","a");//compare the user id to write with all previous ids present in file 
		count++;
		int m;

		if( count ==1) //First user id is always to be written
		{
			fputs(s,fp);
			fputs("\n",fp);
			fclose(fp);
		}
		else
		{
			strcpy(j,s);

			fclose(fp);
			flag=readfileforout(j,count);
			fp=fopen("user.TXT","a");
			if((flag==1) && count !=1)
				{
				fputs(s,fp);
				fputs("\n",fp);
				fclose(fp);
				}

			else if((flag!=1) && (count!=1)) //Not writing duplicate id 
				{
				count--;
				printf("Last User name is already present \n");
				fclose(fp);
				} 

		} 

	} 
} 


void read()
//This function is for viewing the whole file 
//This has not be used as just for refernce for the method of reading 
{
	char s[80];
	FILE *fp;
	fp = fopen ( "user.TXT", "r" ) ;
	if (fp == NULL)
	{
		puts("Cannot open file") ;
		exit(0);
	}
	while ( fgets ( s, 79, fp ) != NULL )
	printf ( "%s",s) ;
	fclose ( fp ) ;

}

//This function makes the hash table
void usr(int z)
{	int w;
	int x;
	int l=0;
	int t=0;
	int i=0;
	int j=0;
	char pass[80];
	char user[80];
	char s[80];
	FILE *fp;
	fp = fopen ( "user.TXT", "r" ) ;
	if (fp == NULL)
	{
	puts("Cannot open file") ;
	exit(0);
	}
	while ( fgets ( s, 79, fp ) != NULL )

	{	
		int fi=0; 
		int ift=0;
		int key =0;
		w=0;
		w++;
		i=0;
 		j=0;
		while(s[i]!=32)
		{

			i++;
		}
		l=0;
		for(t=i;t<=strlen(s)-1;t++)
		{
			if((s[t]!=10) &&(s[t]!=32))
			{
				pass[l]=s[t];
				l++;
			}

		}	
		pass[t]='\0';

//Read password
		for (j=0;j<i;j++)
		{
			user[j]=s[j];
		}
		user[j]='\0';

		printf("\n%s ",user);
//Read useraname
		if(z==1)
		ift=ascii(user);//if 1st hash function
		else if(z==2)
		ift=ascii2(user);//if 2nd hash function
		else if(z==3)
		ift =ascii3(user);//if 3dr hash function

		fi=probe(ift); //get correct slot to store
		
		strcpy(p1[fi].username,user); //store username
		printf("%s",pass);
		strcpy(p1[fi].password,pass);//store password


		}
		fclose ( fp ) ;



}

//The file reading function implemented to read user id and password sepeately
int readfileforout(char j[80],int count)
{ //this function also implements preventing duplicacy 
// it sees if user id to be entered is not already entered
	int k=0;
	int flag=0;
	int i=0;
	int u =0;
	char p[80];
	char ch;
	FILE *fp;
	fp = fopen ( "user.TXT", "r" ) ;
	if (fp == NULL)
	{
		puts("Cannot open file") ;
		exit(0);
	}

	fseek(fp,0,SEEK_SET);//read file from beginning everytime
	while ( fgets ( p, 79, fp ) != NULL )
	{ //check this user id with all uids there -p 

		u++;

		i=0;
		flag=0;

	while (j[i]!=32)
	{ 
		if(p[i]!=j[i])
			{  //different uid from p

				flag=1;			
				break;
		
			}
		else if(p[i]==j[i])
			{
			i++;
			flag =0;
			}
	}


	if (flag ==0)
	{
		fclose(fp); 
		return flag;
	}
}
// you can't have spaces before or in username
//count is no of elements in the file






fclose ( fp ) ;

k= flag;
return k;


}


//This stores user ids and passwords in hash tables,calls linear probing fuctions and hash functions
void ask(char user1[80],char pass1[80],int zz)
	{	
		flagest=0;
		ric=0;

		setbuf(stdin,NULL);
 		int t=0;
		int fi=0;
		int om=0;
		int m=0;

		if(zz==1) //if 1st hash function

		{
			t=ascii(user1);
		}
		else if(zz==2) // if 2nd hash function
		{

			setbuf(stdin,NULL);
			t=ascii2(user1);

		}

		else if(zz==3) //if 3rd hash function
		

		{		
			t=ascii3(user1);
		}


		m=0;

		if((strcmp(p1[t].username,user1)==0) )
		{
			if((strcmp(p1[t].password,pass1)==0) )
				{	
					printf("Slot in hash table is%d ",t);

					printf("\nPassword has Matched,Logged IN ");//Right password
		
				}		 
			else
				{
					printf("\n Password is wrong"); //wrong password
					flagest=1;
				}
		}



		else
		{
			int mn=0;
 			om=0;

			while(om!=40 || (strcmp(p1[t].username,"")!=0) )//Will have to do probing
			{

				if((strcmp(p1[t].username,user1)==0) )//Matching username
				{
					if((strcmp(p1[t].password,pass1)==0) )//Matching password
					{
						printf("PassWord has Matched .You have logged in\n");
						printf("Slot in Hash table is %d",t);
						break;
					}
					else
					{
						printf("Password has NOT Matched");
						flagest=1;
						break;

					}

				}
				else
				{		//searching as can be stored else where due to probing
					om++; //implement probing
					mn=(t+1)%40;
					t=mn;

				}
 				if(om==40) //scanned entire probable portion ,as maximum 40 probes
					{
						ric=1;
						break;
 					}
			}//while

				if(ric==1)//If on scanning hash table after probing uid is not existing
					printf("Username You entered does not exist");
		}//else


	}	




void main()
{

		int prob;
		
		char ch='y';
		int i=0;
		char user1[80];
		char pass1[80];
		int counter=0;
		//filewrite();

		printf("\n Enter 1 to use hashing function where sum of ascii values is taken ");
		printf("\n Enter 2 to use hashing function where multiplication hash function is used ");
		printf("\n Enter 3 to use hashing whoch makes use of length and first CHARCTER ");
		scanf("%d",&prob);
		if(prob==1) //1 st hash function called
		{
			
			usr(1);
			printf("\nPlease enter your username\n");
			scanf("%s",&user1);
			printf("Please enter your password\n");
			scanf("%s",&pass1);
		
			ask(user1,pass1,1);
			counter++; //counter as maximum 3 tries





			if((flagest==1) || (ric==1))
			{
				while(counter<3 && ((flagest==1)||(ric==1))) //giving user 3 tries
				{
					printf("\nWant to try again,press 'y'");
					scanf("%s",&ch);
					if((ch=='y'|| ch =='Y') )
					{
						printf("Please enter your username");
						scanf("%s",&user1);
						printf("Please enter your password");
						scanf("%s",&pass1);
						ask(user1,pass1,1);
						counter++;
					}
					else
					break;
				}
				if(counter==3   && ((flagest==1)||(ric==1)))
				printf("\n Account Locked"); //Account locked after 3 tries
				
			}
		}		


		else if(prob==2) //2nd hash function called
		{
			usr(2);
			printf("\nPlease enter your username\n");
			scanf("%s",&user1);
			printf("Please enter your password\n");
			scanf("%s",&pass1);
			ask(user1,pass1,2);
			counter++; //To keep track of no of tries






			if((flagest==1) || (ric==1))
			{
			while(counter<3 && ((flagest==1)||(ric==1)))//To give user 3 tries if wrong
			{
				printf("\nWant to try again,press 'y'");
				scanf("%s",&ch);
				if((ch=='y'|| ch =='Y') )
				{
					printf("Please enter your username");
					scanf("%s",&user1);
					printf("Please enter your password");
					scanf("%s",&pass1);
					ask(user1,pass1,2);
					counter++;
				}
				else
				break;
				}
			
				if(counter==3 && ((flagest==1)||(ric==1)) )
				printf("\n Account Locked"); //3 incorrect,account locked
			}
			}
	
		else if(prob==3) //third hash function called
		{
		usr(3);
		printf("\nPlease enter your username\n");
		scanf("%s",&user1);
		printf("Please enter your password\n");
		scanf("%s",&pass1);
		ask(user1,pass1,3);
		counter++; //keep track of number of tries






		if((flagest==1) || (ric==1))
		{
			while(counter<3 && ((flagest==1)||(ric==1))) //to give user maximum 3 tries
			{
				printf("\nWant to try again,press 'y'");
				scanf("%s",&ch);
				if((ch=='y'|| ch =='Y') )
				{
					printf("Please enter your username");
					scanf("%s",&user1);
					printf("Please enter your password");
					scanf("%s",&pass1);
					ask(user1,pass1,3);
					counter++;
				}
				else
				break;
			}
		
		
				if(counter==3 && ((flagest==1)||(ric==1)))
				printf("\n Account Locked"); //locking acount if 3 times incorrect
		}
	}



}




